﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Remoting.Messaging;
using System.Security.Cryptography.X509Certificates;

using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Derbster.Domain.Test
{
    [TestClass]
    public class LineupUnitTest : ContractUnitTest
    {
        private Match _testMatch;
        private Lineup _testLineup;
        private CommandManager _commandManager;

        [TestInitialize]
        public void TestSetup()
        {
            _testMatch = TestHelper.CreateTestMatch(true, true, "TestMatch");
            _testMatch.BeginMatch();
            _testMatch.BeginPeriod();
            _testLineup = _testMatch.CurrentJam.FirstTeamLineup;
            _commandManager = new CommandManager();
            _commandManager.Clear();
        }

        [TestMethod]
        public void TestCreateNew()
        {
            var newLineup = new Lineup();
            Assert.IsNotNull(newLineup);
        }

        [TestMethod]
        public void TestCreateNewBad()
        {
            var newLineup = new Lineup();
            var skater = _testMatch.FirstTeamRoster.Skip(2).First();
            newLineup.Blockers = new HashSet<Player>();
            newLineup.Blockers.Add(skater);
            newLineup.Jammer = skater;
            Assert.IsNotNull(newLineup);
            Assert.IsFalse(newLineup.VerifyLineup());
        }

        [TestMethod]
        public void CreateBlockerOnly()
        {
            var newLineup = new Lineup(_testMatch.CurrentJam, 
                new HashSet<Player>(_testMatch.FirstTeamRoster.Skip(2).Take(4).ToList()));
            Assert.IsNotNull(newLineup);
            Assert.IsTrue(newLineup.Contains(_testMatch.FirstTeamRoster.Skip(2).First()));
        }

        [TestMethod]
        public void CreateJammerAndBlocker()
        {
            var newLineup = new Lineup(_testMatch.CurrentJam, 
                _testMatch.FirstTeamRoster.Skip(1).First(),
                new HashSet<Player>(_testMatch.FirstTeamRoster.Skip(2).Take(4).ToList()));
            Assert.IsNotNull(newLineup);
            Assert.IsTrue(newLineup.Jammer == _testMatch.FirstTeamRoster.Skip(1).First());
            Assert.IsTrue(newLineup.Contains(_testMatch.FirstTeamRoster.Skip(2).First()));
        }
        [TestMethod]
        public void CreateJammerPivotAndBlocker()
        {
            var newLineup = new Lineup(_testMatch.CurrentJam, 
                _testMatch.FirstTeamRoster.Skip(1).First(),
                _testMatch.FirstTeamRoster.Skip(2).First(),
                new HashSet<Player>(_testMatch.FirstTeamRoster.Skip(4).Take(3).ToList()));
            Assert.IsNotNull(newLineup);
            Assert.IsTrue(newLineup.Jammer == _testMatch.FirstTeamRoster.Skip(1).First());
            Assert.IsTrue(newLineup.Pivot == _testMatch.FirstTeamRoster.Skip(2).First());
            Assert.IsTrue(newLineup.Contains(_testMatch.FirstTeamRoster.Skip(4).First()));
        }

        [TestMethod]
        public void TestAddJammer()
        {
            var player = _testMatch.FirstTeamRoster.Players.Skip(1).First();
            var player2 = _testMatch.FirstTeamRoster.Players.Skip(2).First();
            _testLineup.AddBlocker(player2);
            _testLineup.AddJammer(player);
            Assert.IsTrue(_testLineup.Jammer == player);
            _commandManager.Undo();
            Assert.IsNull(_testLineup.Jammer);
            _commandManager.Redo();
            Assert.IsTrue(_testLineup.Jammer == player);
        }

        [TestMethod]
        public void TestAddJammerTwice()
        {
            bool throws = false;
            var player = _testMatch.FirstTeamRoster.Players.Skip(1).First();
            var player2 = _testMatch.FirstTeamRoster.Players.Skip(3).First();
            _testLineup.AddJammer(player);
            try
            {
                _testLineup.AddJammer(player2);
            }
            catch (Exception)
            {
                throws = true;
            }

            Assert.IsTrue(throws);
        }

        [TestMethod]
        public void TestRemoveLineupNotExisting()
        {
            bool throws = false;
            var player = _testMatch.FirstTeamRoster.Players.Skip(1).First();
            var player2 = _testMatch.FirstTeamRoster.Players.Skip(3).First();
            _testLineup.AddBlocker(player);
            try
            {
                _testLineup.RemoveFromLineup(player2);
            }
            catch (Exception)
            {
                throws = true;
            }

            Assert.IsTrue(throws);
        }

        [TestMethod]
        public void TestAddPivot()
        {
            var player = _testMatch.FirstTeamRoster.Players.Skip(1).First();
            var player2 = _testMatch.FirstTeamRoster.Players.Skip(2).First();
            _testLineup.AddBlocker(player2);
            _testLineup.AddPivot(player);
            Assert.IsTrue(_testLineup.Pivot == player);
            _commandManager.Undo();
            Assert.IsNull(_testLineup.Pivot);
            _commandManager.Redo();
            Assert.IsTrue(_testLineup.Pivot == player);
        }

        [TestMethod]
        public void TestAddPivotTwice()
        {
            bool throws = false;
            var player = _testMatch.FirstTeamRoster.Players.Skip(1).First();
            var player2 = _testMatch.FirstTeamRoster.Players.Skip(3).First();
            _testLineup.AddPivot(player);
            try
            {
                _testLineup.AddPivot(player2);
            }
            catch (Exception)
            {
                throws = true;
            }

            Assert.IsTrue(throws);
        }


        [TestMethod]
        public void TestAddBlocker()
        {
            var player = _testMatch.FirstTeamRoster.Players.Skip(1).First();
            var player2 = _testMatch.FirstTeamRoster.Players.Skip(2).First();
            _testLineup.AddBlocker(player2);
            _testLineup.AddBlocker(player);
            Assert.IsTrue(_testLineup.Blockers.Contains(player));
            _commandManager.Undo();
            Assert.IsFalse(_testLineup.Blockers.Contains(player));
            _commandManager.Redo();
            Assert.IsTrue(_testLineup.Blockers.Contains(player));
        }

        [TestMethod]
        public void TestAddBlockerTwice()
        {
            bool throws = false;
            var player = _testMatch.FirstTeamRoster.Players.Skip(1).First();
            _testLineup.AddBlocker(player);
            try
            {
                _testLineup.AddBlocker(player);
            }
            catch (Exception)
            {
                throws = true;
            }

            Assert.IsTrue(throws);
        }

        [TestMethod]
        public void TestAddAndCorrectJammer()
        {
            var player = _testMatch.FirstTeamRoster.Players.Skip(1).First();
            var player2 = _testMatch.FirstTeamRoster.Players.Skip(3).First();
            _testLineup.AddJammer(player);
            _testLineup.CorrectLineup(player, player2);
            Assert.IsTrue(_testLineup.Jammer == player2);
            _commandManager.Undo();
            Assert.IsTrue(_testLineup.Jammer == player);
            // ReSharper disable HeuristicUnreachableCode
            _commandManager.Redo();
            Assert.IsTrue(_testLineup.Jammer == player2);
            // ReSharper restore HeuristicUnreachableCode
        }
        
        [TestMethod]
        public void TestAddAndCorrectPivot()
        {
            var player = _testMatch.FirstTeamRoster.Players.Skip(1).First();
            var player2 = _testMatch.FirstTeamRoster.Players.Skip(3).First();
            _testLineup.AddPivot(player);
            _testLineup.CorrectLineup(player, player2);
            Assert.IsTrue(_testLineup.Pivot == player2);
            _commandManager.Undo();
            Assert.IsTrue(_testLineup.Pivot == player);
            // ReSharper disable HeuristicUnreachableCode
            _commandManager.Redo();
            Assert.IsTrue(_testLineup.Pivot == player2);
            // ReSharper restore HeuristicUnreachableCode
        }

        [TestMethod]
        public void TestAddAndCorrectBlocker()
        {
            var player = _testMatch.FirstTeamRoster.Players.Skip(1).First();
            var player2 = _testMatch.FirstTeamRoster.Players.Skip(3).First();
            _testLineup.AddBlocker(player);
            _testLineup.CorrectLineup(player, player2);
            Assert.IsTrue(_testLineup.Blockers.Contains(player2));
            Assert.IsFalse(_testLineup.Blockers.Contains(player));
            _commandManager.Undo();
            Assert.IsTrue(_testLineup.Blockers.Contains(player));
            Assert.IsFalse(_testLineup.Blockers.Contains(player2));
            // ReSharper disable HeuristicUnreachableCode
            _commandManager.Redo();
            Assert.IsTrue(_testLineup.Blockers.Contains(player2));
            Assert.IsFalse(_testLineup.Blockers.Contains(player));
            // ReSharper restore HeuristicUnreachableCode
        }

        [TestMethod]
        public void TestAddAndCorrectExisting()
        {
            bool throws = false;
            var player = _testMatch.FirstTeamRoster.Players.Skip(1).First();
            var player2 = _testMatch.FirstTeamRoster.Players.Skip(3).First();
            _testLineup.AddBlocker(player);
            _testLineup.AddBlocker(player2);
            try
            {
                _testLineup.CorrectLineup(player, player2);
            }
            catch (Exception)
            {
                throws = true;
            }

            Assert.IsTrue(throws);
        }

        [TestMethod]
        public void TestAddAndRemoveJammer()
        {
            var player = _testMatch.FirstTeamRoster.Players.Skip(1).First();
            _testLineup.AddJammer(player);
            _testLineup.RemoveFromLineup(player);
            Assert.IsNull(_testLineup.Jammer);
            _commandManager.Undo();
            Assert.IsTrue(_testLineup.Jammer == player);
            _commandManager.Redo();
            Assert.IsNull(_testLineup.Jammer);
        }

        [TestMethod]
        public void TestAddAndRemovePivot()
        {
            var player = _testMatch.FirstTeamRoster.Players.Skip(1).First();
            _testLineup.AddPivot(player);
            _testLineup.RemoveFromLineup(player);
            Assert.IsNull(_testLineup.Pivot);
            _commandManager.Undo();
            Assert.IsTrue(_testLineup.Pivot == player);
            _commandManager.Redo();
            Assert.IsNull(_testLineup.Pivot);
        }

        [TestMethod]
        public void TestAddAndRemoveBlocker()
        {
            var player = _testMatch.FirstTeamRoster.Players.Skip(1).First();
            _testLineup.AddBlocker(player);
            _testLineup.RemoveFromLineup(player);
            Assert.IsFalse(_testLineup.Blockers.Contains(player));
            _commandManager.Undo();
            Assert.IsTrue(_testLineup.Blockers.Contains(player));
            _commandManager.Redo();
            Assert.IsFalse(_testLineup.Blockers.Contains(player));
        }
    }
}
